<?php
declare (strict_types = 1);

namespace app\home\controller;

use app\admin\model\SpecGoods;
use app\common\model\Address;
use app\common\model\CouponLogs;
use app\common\model\CouponReceive;
use app\common\model\OrderGoods;
use app\home\business\OrderBusiness;
use app\home\business\UserBusiness;
use think\exception\HttpException;
use think\facade\Db;
use think\Request;
use think\facade\View;
use think\facade\Log;

class Pay extends Base
{
    /**
     * 支付页面
     */
    public function pay(){

        // 立即付款
        $address_id = \request()->get('id');
        if (!is_numeric($address_id)) {
            View::assign("error_msg","地址参数错误");
            return View::fetch('/error/pay_error');
        }

        # 判断当前地址id是否正确
        $addressInfo = Address::find($address_id);
        $user_id = UserBusiness::getUserId();
        if ($addressInfo['user_id'] != $user_id) {
            View::assign("error_msg","地址与用户不匹配");
            return View::fetch('/error/pay_error');
        }
        $receive_id = \request()->get('receive_id');//有可能不使用优惠卷
        # 优惠卷的信息
        $couponInfo = CouponReceive::fieldRaw('pyg_coupon_receive.*,c.with_amount,c.used_amount')->leftjoin('coupon c','c.id=pyg_coupon_receive.coupon_id')->where('pyg_coupon_receive.id',$receive_id)->select()->toArray();
        $couponInfo = current($couponInfo);
        # 判断当前优惠卷是否已使用
        $is_used = CouponLogs::where('buyer_id',$user_id)//用户id
            ->where('coupon_receive_id',$receive_id)//优惠卷领取的id
            ->where('status','=',1)//是否使用成功
            ->select()->toArray();
        if (count($is_used) >0) {
            View::assign("error_msg","优惠卷不能重复使用");
            return View::fetch('/error/pay_error');
        }

        // 创建订单

        try {
            $orderInfo = OrderBusiness::createOrder($user_id,$addressInfo,$couponInfo);
            View::assign('orderInfo',$orderInfo);
            return View::fetch();

        }catch (HttpException $httpException) {
            View::assign("error_msg",$httpException->getMessage());
            return View::fetch('/error/pay_error');
        }
    }

    /**
     *
     */
    public function payMoney(){

        $order_sn = \request()->post('order_sn');

        # 验证订单
        $orderInfo = \app\common\model\Order::where('order_sn',$order_sn)->select()->toArray();
        if (count($orderInfo) !=1 ) {
            echo "支付失败";
        }

        $orderInfo = current($orderInfo);

        require_once './plugins/alipay/pagepay/service/AlipayTradeService.php';
        require_once './plugins/alipay/pagepay/buildermodel/AlipayTradePagePayContentBuilder.php';

        //商户订单号，商户网站订单系统中唯一订单号，必填
        $out_trade_no = $order_sn;

        //订单名称，必填
        $subject = "品优购商城支付";

        //付款金额，必填
        $total_amount = $orderInfo['total_amount'];

        //商品描述，可空
        $body = "品优购商城支付";

        //构造参数
        $payRequestBuilder = new \AlipayTradePagePayContentBuilder();
        $payRequestBuilder->setBody($body);
        $payRequestBuilder->setSubject($subject);
        $payRequestBuilder->setTotalAmount($total_amount);
        $payRequestBuilder->setOutTradeNo($out_trade_no);

        $config = config('pay.alipay');
        $aop = new \AlipayTradeService($config);

        /**
         * pagePay 电脑网站支付请求
         * @param $builder 业务参数，使用buildmodel中的对象生成。
         * @param $return_url 同步跳转地址，公网可以访问
         * @param $notify_url 异步通知地址，公网可以访问
         * @return $response 支付宝返回的信息
         */
        $response = $aop->pagePay($payRequestBuilder,$config['return_url'],$config['notify_url']);

        //输出表单
        var_dump($response);
    }

    /**
     * 同步回调地址
     * 给用户提示
     * get
     */
    public function asyncNotice(){
//        return "同步回来了...";

        $config = config('pay.alipay');
        require_once './plugins/alipay/pagepay/service/AlipayTradeService.php';


        $arr=$_GET;
        $alipaySevice = new \AlipayTradeService($config);
        $result = $alipaySevice->check($arr);
        Log::info(json_encode($arr));
        /* 实际验证过程建议商户添加以下校验。
        1、商户需要验证该通知数据中的out_trade_no是否为商户系统中创建的订单号，
        2、判断total_amount是否确实为该订单的实际金额（即商户订单创建时的金额），
        3、校验通知中的seller_id（或者seller_email) 是否为out_trade_no这笔单据的对应的操作方（有的时候，一个商户可能有多个seller_id/seller_email）
        4、验证app_id是否为该商户本身。
        */
        if($result) {//验证成功
            /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
            //请在这里加上商户的业务逻辑程序代码

            //——请根据您的业务逻辑来编写程序（以下代码仅作参考）——
            //获取支付宝的通知返回参数，可参考技术文档中页面跳转同步通知参数列表

            //商户订单号
            $out_trade_no = htmlspecialchars($_GET['out_trade_no']);
            $is_order = \app\common\model\Order::where('order_sn',$out_trade_no)->select()->toArray();
            if (count($is_order) !=1 ) {
                echo "支付失败";die();
            }

            $orderInfo = current($is_order);



            //支付宝交易号
            $trade_no = htmlspecialchars($_GET['trade_no']);
            $app_id = htmlspecialchars($_GET['app_id']);
            $total_amount = htmlspecialchars($_GET['total_amount']);

            if ($orderInfo['total_amount'] != $total_amount) {
                echo "金额不一致";die();
            }

            echo "验证成功<br />支付宝交易号：".$trade_no;

            //——请根据您的业务逻辑来编写程序（以上代码仅作参考）——

            /* 实际验证过程建议商户添加以下校验。
           1、商户需要验证该通知数据中的out_trade_no是否为商户系统中创建的订单号，
           2、判断total_amount是否确实为该订单的实际金额（即商户订单创建时的金额），
           3、校验通知中的seller_id（或者seller_email) 是否为out_trade_no这笔单据的对应的操作方（有的时候，一个商户可能有多个seller_id/seller_email）
           4、验证app_id是否为该商户本身。
           */
            if ($app_id != $config['app_id']) {
                //验证失败
                echo "验证失败";
                return View::fetch("pay/payfail");
            }
            View::assign('total_mount',$total_amount);
            return View::fetch("pay/paysuccess");
            /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        }
        else {
            //验证失败
            echo "验证失败";
            return View::fetch("pay/payfail");
        }
    }

    /**
     * 异步回调地址
     * post 支付请求你的
     * 自己模拟
     * 订单状态的更新
     */
    public function syncNotice(){
//        $config = config('pay.alipay');
//        require_once './plugins/alipay/pagepay/service/AlipayTradeService.php';

//        $arr=$_POST;
//        $alipaySevice = new \AlipayTradeService($config);
//        $alipaySevice->writeLog(var_export($_POST,true));
//        $result = $alipaySevice->check($arr);

        # 记录支付日志
        Db::name('pay_log')->insert(['order_sn' => $_POST['out_trade_no'],'json' => json_encode(\request()->all()),'create_time' => time()]);

        $result = true;
        /* 实际验证过程建议商户添加以下校验。
        1、商户需要验证该通知数据中的out_trade_no是否为商户系统中创建的订单号，
        2、判断total_amount是否确实为该订单的实际金额（即商户订单创建时的金额），
        3、校验通知中的seller_id（或者seller_email) 是否为out_trade_no这笔单据的对应的操作方（有的时候，一个商户可能有多个seller_id/seller_email）
        4、验证app_id是否为该商户本身。
        */
        if($result) {//验证成功
            /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
            //请在这里加上商户的业务逻辑程序代


            //——请根据您的业务逻辑来编写程序（以下代码仅作参考）——

            //获取支付宝的通知返回参数，可参考技术文档中服务器异步通知参数列表

            //商户订单号

            $out_trade_no = $_POST['out_trade_no'];
            $is_order = \app\common\model\Order::where('order_sn',$out_trade_no)->select()->toArray();
            if (count($is_order) !=1 ) {
                echo "fail";die();
            }

            $orderInfo = current($is_order);

            //支付宝交易号

            $trade_no = $_POST['trade_no'];

            //交易状态
            $trade_status = $_POST['trade_status'];


            if($_POST['trade_status'] == 'TRADE_FINISHED') {

                //判断该笔订单是否在商户网站中已经做过处理
                //如果没有做过处理，根据订单号（out_trade_no）在商户网站的订单系统中查到该笔订单的详细，并执行商户的业务程序
                //请务必判断请求时的total_amount与通知时获取的total_fee为一致的
                //如果有做过处理，不执行商户的业务程序

                //注意：
                //退款日期超过可退款期限后（如三个月可退款），支付宝系统发送该交易状态通知
            }
            else if ($_POST['trade_status'] == 'TRADE_SUCCESS') {
                //判断该笔订单是否在商户网站中已经做过处理
                if ($orderInfo['order_status'] > 0 && $orderInfo['order_status']!= 7) {
                    echo  'success';die();
                }
                $result = \app\common\model\Order::where('order_sn',$out_trade_no)->update(['order_status' => 1]);
                if (!$result) {
                    echo "fail";die();
                }
                # 更新优惠卷使用情况

                # 判断该订单是否使用优惠卷
                $is_coupon = CouponLogs::where('order_id',$orderInfo['id'])->where('status','=',0)->select()->toArray();
                if (count($is_coupon) > 0 ) {
                    CouponLogs::where('id',$is_coupon['id'])->update(['status' => 1,'update_time' => time()]);
                }
                # 维护库存

                $orderGoods = OrderGoods::where('order_id',$orderInfo['id'])->select()->toArray();// 订单详情
                $spec_ids = array_column($orderGoods,'spec_goods_id',NULL);
                $goods = SpecGoods::whereIn('id',$spec_ids)->select()->toArray();
                $goods = array_column($goods,'store_frozen','id');
                $storeGoods = [];

                foreach ($orderGoods as $item) {
                    $storeGoods[] = [
                        'id' => $item['spec_goods_id'],
                        'store_frozen' =>$goods[$item['spec_goods_id']] - $item['number'],//真正的扣库存、把冻结库存减去
                    ];
                }
                (new SpecGoods())->saveAll($storeGoods);

                //如果没有做过处理，根据订单号（out_trade_no）在商户网站的订单系统中查到该笔订单的详细，并执行商户的业务程序
                //请务必判断请求时的total_amount与通知时获取的total_fee为一致的
                //如果有做过处理，不执行商户的业务程序
                //注意：
                //付款完成后，支付宝系统发送该交易状态通知

            }
            //——请根据您的业务逻辑来编写程序（以上代码仅作参考）——
            echo "success";	//请不要修改或删除
        }else {
            //验证失败
            echo "fail";

        }
    }

    /**
     * 计划任务
     * crontab
     */
    public function store(){
        # 检验订单是否有超时的
    }
}
